
package com.huaweicloud.haydn.delivercore.agent.utils;

import static com.huaweicloud.haydn.delivercore.agent.config.Constants.FILETYPE_ZIP;
import static com.huaweicloud.haydn.delivercore.agent.config.Constants.SYS_URL;

import com.huaweicloud.haydn.delivercore.agent.common.exception.BusinessErrorEnum;
import com.huaweicloud.haydn.delivercore.agent.common.exception.BusinessException;
import com.huaweicloud.haydn.delivercore.agent.entity.ZipFileEntity;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 功能描述
 *
 * @since 2023-02-03
 */
@Slf4j
@Component
public class ZipUtil {
    public void execZip(String fileName, String type, String zipName) {
        net.lingala.zip4j.ZipFile zipFile = null;
        ZipOutputStream zipOutputStream = null;
        File csvFile = null;
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            File file = new File(System.getProperty(SYS_URL), zipName + "." + FILETYPE_ZIP);
            if (validatePath(file.getCanonicalPath())) {
                throw new BusinessException(BusinessErrorEnum.BASE_BAD_REQUEST);
            }
            if (file.exists()) {
                zipFile = new net.lingala.zip4j.ZipFile(file);
                removeOutdateFile(zipFile, fileName);
                zipFile.addFile(new File(System.getProperty(SYS_URL) + File.separator + fileName), new ZipParameters());
            } else {
                boolean newFile = file.createNewFile();
                if (!newFile) {
                    throw new IOException();
                }
                outputStream = new FileOutputStream(file);
                if (validatePath(file.getCanonicalPath())) {
                    throw new BusinessException(BusinessErrorEnum.BASE_BAD_REQUEST);
                }
                zipOutputStream = new ZipOutputStream(outputStream);
                zipOutputStream.putNextEntry(new ZipEntry(fileName));
                inputStream = new FileInputStream(System.getProperty(SYS_URL) + File.separator + fileName);
                IOUtils.copy(inputStream, zipOutputStream);
                zipOutputStream.closeEntry();
            }
            // delete temporary files
            csvFile = new File(System.getProperty(SYS_URL) + File.separator + fileName);
        } catch (IOException ioe) {
            log.error(ioe.getMessage());
            log.error("zip error");
        } finally {
            try {
                if (zipFile != null) {
                    zipFile.close();
                }
                if (zipOutputStream != null) {
                    zipOutputStream.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
                FileUtils.deleteQuietly(csvFile);
            } catch (IOException e) {
                log.error("Close Resource failed!");
                log.error(e.getMessage(), e);
            }
        }
    }

    private boolean validatePath(String path) {
        return !path.startsWith(System.getProperty(SYS_URL));
    }

    @SneakyThrows
    private void removeOutdateFile(net.lingala.zip4j.ZipFile zip, String type) {
        List<FileHeader> fileHeaders = zip.getFileHeaders();
        if (CollectionUtils.isEmpty(fileHeaders)) {
            return;
        }
        for (int i = 0; i < fileHeaders.size(); i++) {
            FileHeader fileHeader = fileHeaders.get(i);
            if (fileHeader == null) {
                continue;
            }
            if (fileHeader.getFileName().contains(type)) {
                zip.removeFile(fileHeader);
            }
        }
    }

    public void execZip(List<ZipFileEntity> list, String zipName) {
        net.lingala.zip4j.ZipFile zip = null;
        ZipOutputStream zipOut = null;
        List<File> csvFileList = new ArrayList<>();
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            File file = new File(System.getProperty(SYS_URL), zipName + "." + FILETYPE_ZIP);
            if (validatePath(file.getCanonicalPath())) {
                throw new BusinessException(BusinessErrorEnum.BASE_BAD_REQUEST);
            }
            log.info("excel dir: " + System.getProperty(SYS_URL) + File.separator + "monitorConsistencyResult."
                + FILETYPE_ZIP);
            if (CollectionUtils.isEmpty(list)) {
                return;
            }

            if (file.exists()) {
                zip = new net.lingala.zip4j.ZipFile(file);
                for (int i = 0; i < list.size(); i++) {
                    ZipFileEntity zipFile = list.get(i);
                    String fileName = zipFile.getFileName();
                    removeOutdateFile(zip, fileName);
                    File csvFile = new File(System.getProperty(SYS_URL) + File.separator + fileName);
                    zip.addFile(csvFile, new ZipParameters());
                    csvFileList.add(csvFile);
                }
            } else {
                boolean newFile = file.createNewFile();
                if (!newFile) {
                    throw new IOException();
                }
                fileOutputStream = new FileOutputStream(file);
                if (validatePath(file.getCanonicalPath())) {
                    throw new BusinessException(BusinessErrorEnum.BASE_BAD_REQUEST);
                }
                zipOut = new ZipOutputStream(fileOutputStream);
                for (int i = 0; i < list.size(); i++) {
                    ZipFileEntity zipFile = list.get(i);
                    String fileName = zipFile.getFileName();
                    zipOut.putNextEntry(new ZipEntry(fileName));
                    fileInputStream = new FileInputStream(System.getProperty(SYS_URL) + File.separator + fileName);
                    IOUtils.copy(fileInputStream, zipOut);
                    zipOut.closeEntry();
                    fileInputStream.close();
                    log.info("File {} compressed successfully!", fileName);
                    // delete temporary files
                    File csvFile = new File(System.getProperty(SYS_URL) + File.separator + fileName);
                    csvFileList.add(csvFile);
                }
            }
        } catch (IOException ioe) {
            log.error(ioe.getMessage());
            log.error("zip error");
        } finally {
            try {
                if (zip != null) {
                    zip.close();
                }
                if (zipOut != null) {
                    zipOut.close();
                }
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                csvFileList.forEach(FileUtils::deleteQuietly);
            } catch (IOException e) {
                log.error("Close Resource failed!");
                log.error(e.getMessage(), e);
            }
        }
    }
}
